<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Promise | 房飞跃的博客</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link rel="apple-touch-icon" href="/apple-touch-icon.png">
    <link rel="icon" href="/favicon.ico">
    <link rel="manifest" href="/manifest.json">
    <meta name="description" content="房飞跃的博客">
    <meta name="theme-color" content="#ffffff">
    
    <link rel="preload" href="/assets/css/0.styles.e57fdc06.css" as="style"><link rel="preload" href="/assets/js/app.8c5a7a92.js" as="script"><link rel="preload" href="/assets/js/2.8e30e130.js" as="script"><link rel="preload" href="/assets/js/197.2a8de731.js" as="script"><link rel="preload" href="/assets/js/64.0323ed89.js" as="script"><link rel="prefetch" href="/assets/js/10.e695640a.js"><link rel="prefetch" href="/assets/js/100.fae9757f.js"><link rel="prefetch" href="/assets/js/101.d26f7a9a.js"><link rel="prefetch" href="/assets/js/102.e9b20f43.js"><link rel="prefetch" href="/assets/js/103.6d251ff3.js"><link rel="prefetch" href="/assets/js/104.5de918be.js"><link rel="prefetch" href="/assets/js/105.aead61a1.js"><link rel="prefetch" href="/assets/js/106.09a5decb.js"><link rel="prefetch" href="/assets/js/107.a44fc48a.js"><link rel="prefetch" href="/assets/js/108.cec63522.js"><link rel="prefetch" href="/assets/js/109.db1a4ed7.js"><link rel="prefetch" href="/assets/js/11.769ac82c.js"><link rel="prefetch" href="/assets/js/110.10914d38.js"><link rel="prefetch" href="/assets/js/111.2c0ddf25.js"><link rel="prefetch" href="/assets/js/112.c792ca07.js"><link rel="prefetch" href="/assets/js/113.a769ad8f.js"><link rel="prefetch" href="/assets/js/114.c1dca6a0.js"><link rel="prefetch" href="/assets/js/115.82e1fb4f.js"><link rel="prefetch" href="/assets/js/116.c927762b.js"><link rel="prefetch" href="/assets/js/117.5c14eedf.js"><link rel="prefetch" href="/assets/js/118.24861bb6.js"><link rel="prefetch" href="/assets/js/119.3fafaebf.js"><link rel="prefetch" href="/assets/js/12.23031504.js"><link rel="prefetch" href="/assets/js/120.a9ff8fae.js"><link rel="prefetch" href="/assets/js/121.3eb4b3a1.js"><link rel="prefetch" href="/assets/js/122.ff06cffe.js"><link rel="prefetch" href="/assets/js/123.aaf767a6.js"><link rel="prefetch" href="/assets/js/124.4daf257a.js"><link rel="prefetch" href="/assets/js/125.e7e71d3f.js"><link rel="prefetch" href="/assets/js/126.cdee6d86.js"><link rel="prefetch" href="/assets/js/127.aa133c3f.js"><link rel="prefetch" href="/assets/js/128.a8e7d8b2.js"><link rel="prefetch" href="/assets/js/129.dcca2d84.js"><link rel="prefetch" href="/assets/js/13.f37f647e.js"><link rel="prefetch" href="/assets/js/130.3925fb20.js"><link rel="prefetch" href="/assets/js/131.a3a759ed.js"><link rel="prefetch" href="/assets/js/132.84bb9bf9.js"><link rel="prefetch" href="/assets/js/133.30fceda7.js"><link rel="prefetch" href="/assets/js/134.e02f66bf.js"><link rel="prefetch" href="/assets/js/135.71a35d7f.js"><link rel="prefetch" href="/assets/js/136.77762773.js"><link rel="prefetch" href="/assets/js/137.b9741de3.js"><link rel="prefetch" href="/assets/js/138.59b64aa0.js"><link rel="prefetch" href="/assets/js/139.d81e68a1.js"><link rel="prefetch" href="/assets/js/14.0091824d.js"><link rel="prefetch" href="/assets/js/140.68388ddb.js"><link rel="prefetch" href="/assets/js/141.e69cc877.js"><link rel="prefetch" href="/assets/js/142.65fc1806.js"><link rel="prefetch" href="/assets/js/143.4f1e9b3d.js"><link rel="prefetch" href="/assets/js/144.5cf4bdda.js"><link rel="prefetch" href="/assets/js/145.1a1cdb18.js"><link rel="prefetch" href="/assets/js/146.ef4fe2c3.js"><link rel="prefetch" href="/assets/js/147.f5e5d206.js"><link rel="prefetch" href="/assets/js/148.07c7208f.js"><link rel="prefetch" href="/assets/js/149.fb71df8d.js"><link rel="prefetch" href="/assets/js/15.4e1991f3.js"><link rel="prefetch" href="/assets/js/150.771bcbfe.js"><link rel="prefetch" href="/assets/js/151.de02cd55.js"><link rel="prefetch" href="/assets/js/152.6a5b243d.js"><link rel="prefetch" href="/assets/js/153.c1c426d2.js"><link rel="prefetch" href="/assets/js/154.51e08a99.js"><link rel="prefetch" href="/assets/js/155.ab801c7a.js"><link rel="prefetch" href="/assets/js/156.e62111f0.js"><link rel="prefetch" href="/assets/js/157.67f19eb7.js"><link rel="prefetch" href="/assets/js/158.3e57553c.js"><link rel="prefetch" href="/assets/js/159.f01ea56a.js"><link rel="prefetch" href="/assets/js/16.aafe549d.js"><link rel="prefetch" href="/assets/js/160.81468500.js"><link rel="prefetch" href="/assets/js/161.8341c4c9.js"><link rel="prefetch" href="/assets/js/162.18cd1d1e.js"><link rel="prefetch" href="/assets/js/163.2ed65e27.js"><link rel="prefetch" href="/assets/js/164.1c0adbfd.js"><link rel="prefetch" href="/assets/js/165.4382f96e.js"><link rel="prefetch" href="/assets/js/166.47ad10ec.js"><link rel="prefetch" href="/assets/js/167.ee3e3de3.js"><link rel="prefetch" href="/assets/js/168.1273ebb0.js"><link rel="prefetch" href="/assets/js/169.bb6578e0.js"><link rel="prefetch" href="/assets/js/17.4548c40c.js"><link rel="prefetch" href="/assets/js/170.6aef0437.js"><link rel="prefetch" href="/assets/js/171.4818ad12.js"><link rel="prefetch" href="/assets/js/172.7f4674ed.js"><link rel="prefetch" href="/assets/js/173.25951cfa.js"><link rel="prefetch" href="/assets/js/174.604b8889.js"><link rel="prefetch" href="/assets/js/175.752d6221.js"><link rel="prefetch" href="/assets/js/176.ee6ccaf2.js"><link rel="prefetch" href="/assets/js/177.df3e7548.js"><link rel="prefetch" href="/assets/js/178.0c05bdea.js"><link rel="prefetch" href="/assets/js/179.fa300396.js"><link rel="prefetch" href="/assets/js/18.4a166581.js"><link rel="prefetch" href="/assets/js/180.78580e5a.js"><link rel="prefetch" href="/assets/js/181.c08c58e9.js"><link rel="prefetch" href="/assets/js/182.425fd44a.js"><link rel="prefetch" href="/assets/js/183.643e0376.js"><link rel="prefetch" href="/assets/js/184.28243fe4.js"><link rel="prefetch" href="/assets/js/185.145fafb0.js"><link rel="prefetch" href="/assets/js/186.9c005fb8.js"><link rel="prefetch" href="/assets/js/187.a1c8a8da.js"><link rel="prefetch" href="/assets/js/188.b78deff0.js"><link rel="prefetch" href="/assets/js/189.86432945.js"><link rel="prefetch" href="/assets/js/19.992da7e4.js"><link rel="prefetch" href="/assets/js/190.b6c616c9.js"><link rel="prefetch" href="/assets/js/191.d2a4a045.js"><link rel="prefetch" href="/assets/js/192.ce93c157.js"><link rel="prefetch" href="/assets/js/193.f45b56e8.js"><link rel="prefetch" href="/assets/js/194.60166b01.js"><link rel="prefetch" href="/assets/js/195.fea0fdcc.js"><link rel="prefetch" href="/assets/js/196.7f9353e4.js"><link rel="prefetch" href="/assets/js/198.6f3d807b.js"><link rel="prefetch" href="/assets/js/199.75028922.js"><link rel="prefetch" href="/assets/js/20.e27836ed.js"><link rel="prefetch" href="/assets/js/200.36fbe8e0.js"><link rel="prefetch" href="/assets/js/201.ca3a3d7d.js"><link rel="prefetch" href="/assets/js/202.8cc508cd.js"><link rel="prefetch" href="/assets/js/203.eb6662a4.js"><link rel="prefetch" href="/assets/js/204.a75edc0d.js"><link rel="prefetch" href="/assets/js/205.77cc7661.js"><link rel="prefetch" href="/assets/js/206.7cfc88ae.js"><link rel="prefetch" href="/assets/js/207.9d5b5377.js"><link rel="prefetch" href="/assets/js/208.9308a3b3.js"><link rel="prefetch" href="/assets/js/209.cbee10e7.js"><link rel="prefetch" href="/assets/js/21.9bc4424f.js"><link rel="prefetch" href="/assets/js/210.3dbd53b3.js"><link rel="prefetch" href="/assets/js/211.ffc0051e.js"><link rel="prefetch" href="/assets/js/212.420b9a23.js"><link rel="prefetch" href="/assets/js/213.da84f0aa.js"><link rel="prefetch" href="/assets/js/214.2a5308ff.js"><link rel="prefetch" href="/assets/js/215.bc87143e.js"><link rel="prefetch" href="/assets/js/216.f099b04d.js"><link rel="prefetch" href="/assets/js/217.39cc059e.js"><link rel="prefetch" href="/assets/js/218.3b588871.js"><link rel="prefetch" href="/assets/js/219.8c7c7f40.js"><link rel="prefetch" href="/assets/js/22.287b20ef.js"><link rel="prefetch" href="/assets/js/220.6a490188.js"><link rel="prefetch" href="/assets/js/221.a06fe7b9.js"><link rel="prefetch" href="/assets/js/222.0da34a82.js"><link rel="prefetch" href="/assets/js/223.6d6abad9.js"><link rel="prefetch" href="/assets/js/224.de157359.js"><link rel="prefetch" href="/assets/js/225.c733d3d1.js"><link rel="prefetch" href="/assets/js/226.039d453b.js"><link rel="prefetch" href="/assets/js/227.dbe84815.js"><link rel="prefetch" href="/assets/js/228.4850e3f3.js"><link rel="prefetch" href="/assets/js/229.322215a9.js"><link rel="prefetch" href="/assets/js/23.c1fc6d56.js"><link rel="prefetch" href="/assets/js/230.2469fb45.js"><link rel="prefetch" href="/assets/js/231.a77224ae.js"><link rel="prefetch" href="/assets/js/232.56534eb1.js"><link rel="prefetch" href="/assets/js/233.f69b682d.js"><link rel="prefetch" href="/assets/js/234.33fecaf9.js"><link rel="prefetch" href="/assets/js/235.3152a6d8.js"><link rel="prefetch" href="/assets/js/236.4a45a619.js"><link rel="prefetch" href="/assets/js/237.683796c5.js"><link rel="prefetch" href="/assets/js/238.4183baab.js"><link rel="prefetch" href="/assets/js/239.967342f3.js"><link rel="prefetch" href="/assets/js/24.c4266153.js"><link rel="prefetch" href="/assets/js/240.4ebdaa3e.js"><link rel="prefetch" href="/assets/js/241.3853f81e.js"><link rel="prefetch" href="/assets/js/242.0be00241.js"><link rel="prefetch" href="/assets/js/243.27a16565.js"><link rel="prefetch" href="/assets/js/244.4b6c0842.js"><link rel="prefetch" href="/assets/js/245.0ff5b09e.js"><link rel="prefetch" href="/assets/js/246.ec9708bc.js"><link rel="prefetch" href="/assets/js/247.33dd2e3f.js"><link rel="prefetch" href="/assets/js/248.e095c83d.js"><link rel="prefetch" href="/assets/js/249.e35dae0b.js"><link rel="prefetch" href="/assets/js/25.0bd19957.js"><link rel="prefetch" href="/assets/js/250.b7dda30b.js"><link rel="prefetch" href="/assets/js/251.373c219f.js"><link rel="prefetch" href="/assets/js/252.f02d8652.js"><link rel="prefetch" href="/assets/js/253.0129ab3b.js"><link rel="prefetch" href="/assets/js/254.05bc87ae.js"><link rel="prefetch" href="/assets/js/255.93959060.js"><link rel="prefetch" href="/assets/js/256.036268bb.js"><link rel="prefetch" href="/assets/js/257.4cfe4c46.js"><link rel="prefetch" href="/assets/js/258.70f49e1e.js"><link rel="prefetch" href="/assets/js/259.e92d7a7e.js"><link rel="prefetch" href="/assets/js/26.cd8cc5bc.js"><link rel="prefetch" href="/assets/js/260.24ecb139.js"><link rel="prefetch" href="/assets/js/261.32f0c433.js"><link rel="prefetch" href="/assets/js/262.aca4b5e9.js"><link rel="prefetch" href="/assets/js/263.0051554a.js"><link rel="prefetch" href="/assets/js/264.063d3092.js"><link rel="prefetch" href="/assets/js/265.de1fe60c.js"><link rel="prefetch" href="/assets/js/266.4407a594.js"><link rel="prefetch" href="/assets/js/267.9318dca9.js"><link rel="prefetch" href="/assets/js/268.b9696b4c.js"><link rel="prefetch" href="/assets/js/269.21743bc6.js"><link rel="prefetch" href="/assets/js/27.e0c9a2d1.js"><link rel="prefetch" href="/assets/js/270.64175904.js"><link rel="prefetch" href="/assets/js/271.ab988e51.js"><link rel="prefetch" href="/assets/js/272.40190656.js"><link rel="prefetch" href="/assets/js/273.124f97d6.js"><link rel="prefetch" href="/assets/js/274.ac2ae949.js"><link rel="prefetch" href="/assets/js/275.84112c31.js"><link rel="prefetch" href="/assets/js/276.5cd3a2f1.js"><link rel="prefetch" href="/assets/js/277.dfd266d2.js"><link rel="prefetch" href="/assets/js/278.2c22b507.js"><link rel="prefetch" href="/assets/js/279.143630b9.js"><link rel="prefetch" href="/assets/js/28.ee8b098b.js"><link rel="prefetch" href="/assets/js/280.e52e72d5.js"><link rel="prefetch" href="/assets/js/281.fa255716.js"><link rel="prefetch" href="/assets/js/282.33cf3680.js"><link rel="prefetch" href="/assets/js/283.8aaeb880.js"><link rel="prefetch" href="/assets/js/284.cce2c80c.js"><link rel="prefetch" href="/assets/js/285.649e1ab2.js"><link rel="prefetch" href="/assets/js/286.93d1a5fb.js"><link rel="prefetch" href="/assets/js/287.95ecc60d.js"><link rel="prefetch" href="/assets/js/288.d0316c60.js"><link rel="prefetch" href="/assets/js/289.96b0da90.js"><link rel="prefetch" href="/assets/js/29.f1800df7.js"><link rel="prefetch" href="/assets/js/290.a0ec1eb0.js"><link rel="prefetch" href="/assets/js/291.000c9293.js"><link rel="prefetch" href="/assets/js/292.aa442a45.js"><link rel="prefetch" href="/assets/js/293.ad41a62d.js"><link rel="prefetch" href="/assets/js/294.d01fa093.js"><link rel="prefetch" href="/assets/js/295.988cbaa2.js"><link rel="prefetch" href="/assets/js/296.b4376d7c.js"><link rel="prefetch" href="/assets/js/297.53d3839b.js"><link rel="prefetch" href="/assets/js/298.e41d3af5.js"><link rel="prefetch" href="/assets/js/299.7530e3f7.js"><link rel="prefetch" href="/assets/js/3.0318d431.js"><link rel="prefetch" href="/assets/js/30.e022632d.js"><link rel="prefetch" href="/assets/js/300.b89cf9f0.js"><link rel="prefetch" href="/assets/js/301.538c5d13.js"><link rel="prefetch" href="/assets/js/302.e61e98d4.js"><link rel="prefetch" href="/assets/js/303.e69fdf1f.js"><link rel="prefetch" href="/assets/js/304.12cf05d2.js"><link rel="prefetch" href="/assets/js/305.05630898.js"><link rel="prefetch" href="/assets/js/306.4423e4cb.js"><link rel="prefetch" href="/assets/js/307.ec499705.js"><link rel="prefetch" href="/assets/js/308.eae04a19.js"><link rel="prefetch" href="/assets/js/309.e8cdb29d.js"><link rel="prefetch" href="/assets/js/31.a2dfbc5f.js"><link rel="prefetch" href="/assets/js/310.3770a9fc.js"><link rel="prefetch" href="/assets/js/311.79ae7adb.js"><link rel="prefetch" href="/assets/js/312.fd3baefc.js"><link rel="prefetch" href="/assets/js/313.895f6dcd.js"><link rel="prefetch" href="/assets/js/314.85943d2f.js"><link rel="prefetch" href="/assets/js/315.69631810.js"><link rel="prefetch" href="/assets/js/316.b025621c.js"><link rel="prefetch" href="/assets/js/317.7b7974aa.js"><link rel="prefetch" href="/assets/js/318.972a129d.js"><link rel="prefetch" href="/assets/js/319.65a4d2cf.js"><link rel="prefetch" href="/assets/js/32.b143e718.js"><link rel="prefetch" href="/assets/js/320.e5635579.js"><link rel="prefetch" href="/assets/js/321.845573fa.js"><link rel="prefetch" href="/assets/js/322.0f95ad9a.js"><link rel="prefetch" href="/assets/js/323.f7d22184.js"><link rel="prefetch" href="/assets/js/324.eb027f24.js"><link rel="prefetch" href="/assets/js/325.f54af6ec.js"><link rel="prefetch" href="/assets/js/326.7a921d9f.js"><link rel="prefetch" href="/assets/js/327.e9c43c17.js"><link rel="prefetch" href="/assets/js/328.586efc33.js"><link rel="prefetch" href="/assets/js/329.47017c3f.js"><link rel="prefetch" href="/assets/js/33.e17e09ac.js"><link rel="prefetch" href="/assets/js/330.81032fbd.js"><link rel="prefetch" href="/assets/js/331.ce9966db.js"><link rel="prefetch" href="/assets/js/332.c28e794e.js"><link rel="prefetch" href="/assets/js/333.4564d08a.js"><link rel="prefetch" href="/assets/js/334.3b421837.js"><link rel="prefetch" href="/assets/js/335.b2b74b9d.js"><link rel="prefetch" href="/assets/js/336.9dd1e510.js"><link rel="prefetch" href="/assets/js/337.03042431.js"><link rel="prefetch" href="/assets/js/338.1bc0b80f.js"><link rel="prefetch" href="/assets/js/339.e517fc5c.js"><link rel="prefetch" href="/assets/js/34.f287ac3d.js"><link rel="prefetch" href="/assets/js/340.f90d2df3.js"><link rel="prefetch" href="/assets/js/341.eccb4ec1.js"><link rel="prefetch" href="/assets/js/342.b3386439.js"><link rel="prefetch" href="/assets/js/343.2ee6901d.js"><link rel="prefetch" href="/assets/js/344.e6913fc7.js"><link rel="prefetch" href="/assets/js/345.a72760e7.js"><link rel="prefetch" href="/assets/js/346.13984d25.js"><link rel="prefetch" href="/assets/js/347.6b59cbaf.js"><link rel="prefetch" href="/assets/js/348.f43d5e47.js"><link rel="prefetch" href="/assets/js/349.fe8641cf.js"><link rel="prefetch" href="/assets/js/35.5a1dace7.js"><link rel="prefetch" href="/assets/js/350.0ceb9652.js"><link rel="prefetch" href="/assets/js/351.08e70696.js"><link rel="prefetch" href="/assets/js/352.958f535b.js"><link rel="prefetch" href="/assets/js/353.51463d78.js"><link rel="prefetch" href="/assets/js/354.6169e165.js"><link rel="prefetch" href="/assets/js/355.10447463.js"><link rel="prefetch" href="/assets/js/356.32983151.js"><link rel="prefetch" href="/assets/js/357.39e998b6.js"><link rel="prefetch" href="/assets/js/358.1f40aee7.js"><link rel="prefetch" href="/assets/js/359.d1e82e86.js"><link rel="prefetch" href="/assets/js/36.b6f4332a.js"><link rel="prefetch" href="/assets/js/360.9096bf48.js"><link rel="prefetch" href="/assets/js/361.e2c0815a.js"><link rel="prefetch" href="/assets/js/362.66983024.js"><link rel="prefetch" href="/assets/js/363.d7f0691d.js"><link rel="prefetch" href="/assets/js/364.d96ddc65.js"><link rel="prefetch" href="/assets/js/365.c92ad624.js"><link rel="prefetch" href="/assets/js/366.dfd66280.js"><link rel="prefetch" href="/assets/js/367.01503521.js"><link rel="prefetch" href="/assets/js/368.8d83b9c1.js"><link rel="prefetch" href="/assets/js/369.f8e08a4f.js"><link rel="prefetch" href="/assets/js/37.f1a16008.js"><link rel="prefetch" href="/assets/js/370.70b912f3.js"><link rel="prefetch" href="/assets/js/371.dcefb388.js"><link rel="prefetch" href="/assets/js/372.a81a499a.js"><link rel="prefetch" href="/assets/js/373.94458b0f.js"><link rel="prefetch" href="/assets/js/374.a406f06f.js"><link rel="prefetch" href="/assets/js/375.87287c02.js"><link rel="prefetch" href="/assets/js/376.26088425.js"><link rel="prefetch" href="/assets/js/377.b9ee096c.js"><link rel="prefetch" href="/assets/js/378.7a1b6fa7.js"><link rel="prefetch" href="/assets/js/379.3e2b62fc.js"><link rel="prefetch" href="/assets/js/38.59f5160c.js"><link rel="prefetch" href="/assets/js/380.d741385f.js"><link rel="prefetch" href="/assets/js/381.afc0104a.js"><link rel="prefetch" href="/assets/js/382.a8c02915.js"><link rel="prefetch" href="/assets/js/383.7fca9756.js"><link rel="prefetch" href="/assets/js/384.d08aa931.js"><link rel="prefetch" href="/assets/js/385.c3ab471f.js"><link rel="prefetch" href="/assets/js/386.7314b80e.js"><link rel="prefetch" href="/assets/js/387.8db3a14a.js"><link rel="prefetch" href="/assets/js/388.f618a3b3.js"><link rel="prefetch" href="/assets/js/389.4d35947d.js"><link rel="prefetch" href="/assets/js/39.3cf9af40.js"><link rel="prefetch" href="/assets/js/390.a8e04e41.js"><link rel="prefetch" href="/assets/js/391.a31e9a62.js"><link rel="prefetch" href="/assets/js/392.d9321e46.js"><link rel="prefetch" href="/assets/js/393.6c4834d0.js"><link rel="prefetch" href="/assets/js/394.fd0a0ea4.js"><link rel="prefetch" href="/assets/js/395.0f27ab48.js"><link rel="prefetch" href="/assets/js/396.70044e25.js"><link rel="prefetch" href="/assets/js/397.07b2c0a6.js"><link rel="prefetch" href="/assets/js/398.ba95a9c5.js"><link rel="prefetch" href="/assets/js/399.8b310fbc.js"><link rel="prefetch" href="/assets/js/4.45f61616.js"><link rel="prefetch" href="/assets/js/40.fcf089d7.js"><link rel="prefetch" href="/assets/js/400.7ff77c6c.js"><link rel="prefetch" href="/assets/js/401.840e0c7c.js"><link rel="prefetch" href="/assets/js/402.a722c16f.js"><link rel="prefetch" href="/assets/js/403.1a3c12fb.js"><link rel="prefetch" href="/assets/js/404.7da4d4a4.js"><link rel="prefetch" href="/assets/js/405.76a07310.js"><link rel="prefetch" href="/assets/js/406.176db1fd.js"><link rel="prefetch" href="/assets/js/407.ff3da33f.js"><link rel="prefetch" href="/assets/js/408.3b4dfb3a.js"><link rel="prefetch" href="/assets/js/409.05692a2e.js"><link rel="prefetch" href="/assets/js/41.3f0a746d.js"><link rel="prefetch" href="/assets/js/410.615dc40b.js"><link rel="prefetch" href="/assets/js/411.e542a59f.js"><link rel="prefetch" href="/assets/js/412.16fc0c97.js"><link rel="prefetch" href="/assets/js/413.b9f30c37.js"><link rel="prefetch" href="/assets/js/414.9629300e.js"><link rel="prefetch" href="/assets/js/415.5c12951e.js"><link rel="prefetch" href="/assets/js/416.3ede10bc.js"><link rel="prefetch" href="/assets/js/417.5bc08adb.js"><link rel="prefetch" href="/assets/js/418.0a54fe32.js"><link rel="prefetch" href="/assets/js/419.97ebd724.js"><link rel="prefetch" href="/assets/js/42.d0fdcdd4.js"><link rel="prefetch" href="/assets/js/420.d3f60a7a.js"><link rel="prefetch" href="/assets/js/421.6b187cc9.js"><link rel="prefetch" href="/assets/js/422.268b38aa.js"><link rel="prefetch" href="/assets/js/423.00f151fe.js"><link rel="prefetch" href="/assets/js/424.5d54e48d.js"><link rel="prefetch" href="/assets/js/425.b0e71df6.js"><link rel="prefetch" href="/assets/js/426.fb5d6c08.js"><link rel="prefetch" href="/assets/js/427.a7a42bdb.js"><link rel="prefetch" href="/assets/js/428.b41b80fb.js"><link rel="prefetch" href="/assets/js/429.aff3b223.js"><link rel="prefetch" href="/assets/js/43.7812871c.js"><link rel="prefetch" href="/assets/js/430.9bded6a2.js"><link rel="prefetch" href="/assets/js/431.fbd064dd.js"><link rel="prefetch" href="/assets/js/432.a0ccaf13.js"><link rel="prefetch" href="/assets/js/433.70729631.js"><link rel="prefetch" href="/assets/js/434.7ff21dc4.js"><link rel="prefetch" href="/assets/js/435.ba6f0c33.js"><link rel="prefetch" href="/assets/js/436.abcca44e.js"><link rel="prefetch" href="/assets/js/437.2b2333cb.js"><link rel="prefetch" href="/assets/js/438.93ea3d14.js"><link rel="prefetch" href="/assets/js/439.c1b946ea.js"><link rel="prefetch" href="/assets/js/44.d2bbbf62.js"><link rel="prefetch" href="/assets/js/440.a5c5071e.js"><link rel="prefetch" href="/assets/js/441.bad7a6f2.js"><link rel="prefetch" href="/assets/js/442.97a45e71.js"><link rel="prefetch" href="/assets/js/443.9dd7a744.js"><link rel="prefetch" href="/assets/js/444.b2e74ec9.js"><link rel="prefetch" href="/assets/js/445.181b11ad.js"><link rel="prefetch" href="/assets/js/446.1d43ea57.js"><link rel="prefetch" href="/assets/js/447.a75ca861.js"><link rel="prefetch" href="/assets/js/448.7e177e61.js"><link rel="prefetch" href="/assets/js/449.0e124a1f.js"><link rel="prefetch" href="/assets/js/45.2181b5c6.js"><link rel="prefetch" href="/assets/js/450.d18c5137.js"><link rel="prefetch" href="/assets/js/451.0296f837.js"><link rel="prefetch" href="/assets/js/452.1f5d56a5.js"><link rel="prefetch" href="/assets/js/453.6f67fa9b.js"><link rel="prefetch" href="/assets/js/454.d96cd4e8.js"><link rel="prefetch" href="/assets/js/455.488f2e23.js"><link rel="prefetch" href="/assets/js/456.264d0da2.js"><link rel="prefetch" href="/assets/js/457.329d4d26.js"><link rel="prefetch" href="/assets/js/458.d20d34f9.js"><link rel="prefetch" href="/assets/js/459.dd4fad09.js"><link rel="prefetch" href="/assets/js/46.d69710e9.js"><link rel="prefetch" href="/assets/js/460.e1f8580c.js"><link rel="prefetch" href="/assets/js/461.d47e1ab7.js"><link rel="prefetch" href="/assets/js/462.54b49f34.js"><link rel="prefetch" href="/assets/js/463.2d1bb289.js"><link rel="prefetch" href="/assets/js/464.28d2b2fe.js"><link rel="prefetch" href="/assets/js/465.474d09dd.js"><link rel="prefetch" href="/assets/js/466.3d79bf1d.js"><link rel="prefetch" href="/assets/js/467.0e38992e.js"><link rel="prefetch" href="/assets/js/468.23f8dbdb.js"><link rel="prefetch" href="/assets/js/469.424ab64e.js"><link rel="prefetch" href="/assets/js/47.fa77c18f.js"><link rel="prefetch" href="/assets/js/470.8e15adc4.js"><link rel="prefetch" href="/assets/js/471.e478b277.js"><link rel="prefetch" href="/assets/js/472.75eed247.js"><link rel="prefetch" href="/assets/js/473.676ac02f.js"><link rel="prefetch" href="/assets/js/474.ec676f10.js"><link rel="prefetch" href="/assets/js/475.0b3a7bb3.js"><link rel="prefetch" href="/assets/js/476.1dccc2bf.js"><link rel="prefetch" href="/assets/js/477.19774d6a.js"><link rel="prefetch" href="/assets/js/478.562bcdfb.js"><link rel="prefetch" href="/assets/js/479.0fdf39e1.js"><link rel="prefetch" href="/assets/js/48.55ba7067.js"><link rel="prefetch" href="/assets/js/480.32cb0959.js"><link rel="prefetch" href="/assets/js/481.39744803.js"><link rel="prefetch" href="/assets/js/482.82ff750c.js"><link rel="prefetch" href="/assets/js/483.59be5f3b.js"><link rel="prefetch" href="/assets/js/484.b47730ba.js"><link rel="prefetch" href="/assets/js/485.514e284f.js"><link rel="prefetch" href="/assets/js/486.8d407228.js"><link rel="prefetch" href="/assets/js/487.623afb9a.js"><link rel="prefetch" href="/assets/js/488.d575377d.js"><link rel="prefetch" href="/assets/js/49.369b2ef4.js"><link rel="prefetch" href="/assets/js/5.89e027e6.js"><link rel="prefetch" href="/assets/js/50.32e51808.js"><link rel="prefetch" href="/assets/js/51.48af1f55.js"><link rel="prefetch" href="/assets/js/52.0ff3366f.js"><link rel="prefetch" href="/assets/js/53.f663d530.js"><link rel="prefetch" href="/assets/js/54.57eabb55.js"><link rel="prefetch" href="/assets/js/55.00e0bdd0.js"><link rel="prefetch" href="/assets/js/56.b638bc9a.js"><link rel="prefetch" href="/assets/js/57.68420705.js"><link rel="prefetch" href="/assets/js/58.f0a325a2.js"><link rel="prefetch" href="/assets/js/59.30debc93.js"><link rel="prefetch" href="/assets/js/6.0db48d19.js"><link rel="prefetch" href="/assets/js/60.48490f44.js"><link rel="prefetch" href="/assets/js/61.26a984a9.js"><link rel="prefetch" href="/assets/js/62.f0add27d.js"><link rel="prefetch" href="/assets/js/63.07c42d31.js"><link rel="prefetch" href="/assets/js/65.c159a057.js"><link rel="prefetch" href="/assets/js/66.80e96020.js"><link rel="prefetch" href="/assets/js/67.42eabf7d.js"><link rel="prefetch" href="/assets/js/68.2a7e9954.js"><link rel="prefetch" href="/assets/js/69.4579e421.js"><link rel="prefetch" href="/assets/js/7.037ecfb1.js"><link rel="prefetch" href="/assets/js/70.4e7b95d4.js"><link rel="prefetch" href="/assets/js/71.5df75825.js"><link rel="prefetch" href="/assets/js/72.6239ec2a.js"><link rel="prefetch" href="/assets/js/73.c2458335.js"><link rel="prefetch" href="/assets/js/74.b86599e1.js"><link rel="prefetch" href="/assets/js/75.8d14cab7.js"><link rel="prefetch" href="/assets/js/76.82bf4b00.js"><link rel="prefetch" href="/assets/js/77.f5a890cc.js"><link rel="prefetch" href="/assets/js/78.f3c574f3.js"><link rel="prefetch" href="/assets/js/79.c9c56bf3.js"><link rel="prefetch" href="/assets/js/8.03d32196.js"><link rel="prefetch" href="/assets/js/80.24c4483b.js"><link rel="prefetch" href="/assets/js/81.e6653250.js"><link rel="prefetch" href="/assets/js/82.0da4ae5d.js"><link rel="prefetch" href="/assets/js/83.89a8c965.js"><link rel="prefetch" href="/assets/js/84.56206c88.js"><link rel="prefetch" href="/assets/js/85.0daf7cf7.js"><link rel="prefetch" href="/assets/js/86.0a17b684.js"><link rel="prefetch" href="/assets/js/87.f7cf9412.js"><link rel="prefetch" href="/assets/js/88.22341e3f.js"><link rel="prefetch" href="/assets/js/89.2166c8bb.js"><link rel="prefetch" href="/assets/js/9.a241a058.js"><link rel="prefetch" href="/assets/js/90.9440815d.js"><link rel="prefetch" href="/assets/js/91.5ea69e27.js"><link rel="prefetch" href="/assets/js/92.cea1c8dd.js"><link rel="prefetch" href="/assets/js/93.2e94ab93.js"><link rel="prefetch" href="/assets/js/94.1674ba0c.js"><link rel="prefetch" href="/assets/js/95.c6ba057e.js"><link rel="prefetch" href="/assets/js/96.ee719565.js"><link rel="prefetch" href="/assets/js/97.a814f163.js"><link rel="prefetch" href="/assets/js/98.748b1098.js"><link rel="prefetch" href="/assets/js/99.c6176c0d.js">
    <link rel="stylesheet" href="/assets/css/0.styles.e57fdc06.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/logo.png" alt="房飞跃的博客" class="logo"> <span class="site-name can-hide">房飞跃的博客</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端" class="dropdown-title"><span class="title">前端</span> <span class="arrow down"></span></button> <button type="button" aria-label="前端" class="mobile-dropdown-title"><span class="title">前端</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          Vue
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/books/深入浅出Vue.js/01.html" class="nav-link">
  深入浅出Vue
</a></li><li class="dropdown-subitem"><a href="/front/vue/vue/01.html" class="nav-link">
  Vue
</a></li><li class="dropdown-subitem"><a href="/front/vue/vue-router/01.html" class="nav-link">
  VueRouter
</a></li><li class="dropdown-subitem"><a href="/front/vue/Vuex/01.html" class="nav-link">
  Vuex
</a></li><li class="dropdown-subitem"><a href="/front/vue/vue3/01.html" class="nav-link">
  Vue3核心剖析
</a></li><li class="dropdown-subitem"><a href="/front/vue/Vue知识点简单梳理/01.html" class="nav-link">
  Vue知识点简单梳理
</a></li></ul></li><li class="dropdown-item"><h4>
          React
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/books/深入React技术栈/01.html" class="nav-link">
  深入React技术栈
</a></li><li class="dropdown-subitem"><a href="/front/react/React进阶实践指南/01.html" class="nav-link">
  React进阶实践指南
</a></li><li class="dropdown-subitem"><a href="/front/react/React知识点简单梳理/01.html" class="nav-link">
  React知识点简单梳理
</a></li></ul></li><li class="dropdown-item"><h4>
          混合开发
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/混合开发/01.html" class="nav-link">
  混合开发探究
</a></li></ul></li><li class="dropdown-item"><h4>
          TypeScript
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/ts/极简入门Typescript/01.html" class="nav-link">
  极简入门Typescript
</a></li></ul></li><li class="dropdown-item"><h4>
          Webpack
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/webpack/极简入门webpack/01.html" class="nav-link">
  极简入门
</a></li><li class="dropdown-subitem"><a href="/front/webpack/常见面试题/01.html" class="nav-link">
  常见面试题
</a></li></ul></li><li class="dropdown-item"><h4>
          设计模式
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/设计模式/JS设计模式核心原理和应用实践/01.html" class="nav-link">
  JS设计模式核心原理和应用实践
</a></li></ul></li><li class="dropdown-item"><h4>
          算法和数据结构
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/算法和数据结构/入门级算法/01.html" class="nav-link">
  入门级算法
</a></li><li class="dropdown-subitem"><a href="/front/算法和数据结构/常见算法/01.html" class="nav-link">
  常见算法
</a></li><li class="dropdown-subitem"><a href="/front/算法和数据结构/常见数据结构/01.html" class="nav-link">
  常见数据结构
</a></li><li class="dropdown-subitem"><a href="/front/算法和数据结构/前端算法与数据结构/01.html" class="nav-link">
  前端算法与数据结构
</a></li></ul></li><li class="dropdown-item"><h4>
          基础必备
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/base/html必备/01.html" class="nav-link">
  HTML必备
</a></li><li class="dropdown-subitem"><a href="/front/base/CSS必备/01.html" class="nav-link">
  CSS必备
</a></li><li class="dropdown-subitem"><a href="/front/base/JS基础/01.html" class="nav-link">
  JS基础
</a></li><li class="dropdown-subitem"><a href="/front/base/JS进阶/01.html" class="nav-link">
  JS进阶
</a></li><li class="dropdown-subitem"><a href="/front/base/JS练习/01.html" class="nav-link">
  JS练习
</a></li><li class="dropdown-subitem"><a href="/front/base/网络基础/01.html" class="nav-link">
  网络基础
</a></li><li class="dropdown-subitem"><a href="/books/JS高级程序设计/01.html" class="nav-link">
  JS高级程序设计
</a></li><li class="dropdown-subitem"><a href="/front/base/浏览器相关基础/01.html" class="nav-link">
  浏览器相关基础
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="电子" class="dropdown-title"><span class="title">电子</span> <span class="arrow down"></span></button> <button type="button" aria-label="电子" class="mobile-dropdown-title"><span class="title">电子</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          STM32
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/电子/STM32四轴飞行器/01.html" class="nav-link">
  STM32四轴飞行器
</a></li></ul></li><li class="dropdown-item"><h4>
          Arduino
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/电子/Arduino墙画机/01.html" class="nav-link">
  Arduino墙画机
</a></li><li class="dropdown-subitem"><a href="/电子/Arduino四轴飞行器/01.html" class="nav-link">
  Arduino四轴飞行器
</a></li><li class="dropdown-subitem"><a href="/电子/Arduino四足仿生机器人/01.html" class="nav-link">
  Arduino四足仿生机器人
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="关于" class="dropdown-title"><span class="title">关于</span> <span class="arrow down"></span></button> <button type="button" aria-label="关于" class="mobile-dropdown-title"><span class="title">关于</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/关于我/01.html" class="nav-link">
  关于我
</a></li><li class="dropdown-item"><!----> <a href="https://github.com/fangfeiyue" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Github
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端" class="dropdown-title"><span class="title">前端</span> <span class="arrow down"></span></button> <button type="button" aria-label="前端" class="mobile-dropdown-title"><span class="title">前端</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          Vue
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/books/深入浅出Vue.js/01.html" class="nav-link">
  深入浅出Vue
</a></li><li class="dropdown-subitem"><a href="/front/vue/vue/01.html" class="nav-link">
  Vue
</a></li><li class="dropdown-subitem"><a href="/front/vue/vue-router/01.html" class="nav-link">
  VueRouter
</a></li><li class="dropdown-subitem"><a href="/front/vue/Vuex/01.html" class="nav-link">
  Vuex
</a></li><li class="dropdown-subitem"><a href="/front/vue/vue3/01.html" class="nav-link">
  Vue3核心剖析
</a></li><li class="dropdown-subitem"><a href="/front/vue/Vue知识点简单梳理/01.html" class="nav-link">
  Vue知识点简单梳理
</a></li></ul></li><li class="dropdown-item"><h4>
          React
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/books/深入React技术栈/01.html" class="nav-link">
  深入React技术栈
</a></li><li class="dropdown-subitem"><a href="/front/react/React进阶实践指南/01.html" class="nav-link">
  React进阶实践指南
</a></li><li class="dropdown-subitem"><a href="/front/react/React知识点简单梳理/01.html" class="nav-link">
  React知识点简单梳理
</a></li></ul></li><li class="dropdown-item"><h4>
          混合开发
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/混合开发/01.html" class="nav-link">
  混合开发探究
</a></li></ul></li><li class="dropdown-item"><h4>
          TypeScript
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/ts/极简入门Typescript/01.html" class="nav-link">
  极简入门Typescript
</a></li></ul></li><li class="dropdown-item"><h4>
          Webpack
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/webpack/极简入门webpack/01.html" class="nav-link">
  极简入门
</a></li><li class="dropdown-subitem"><a href="/front/webpack/常见面试题/01.html" class="nav-link">
  常见面试题
</a></li></ul></li><li class="dropdown-item"><h4>
          设计模式
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/设计模式/JS设计模式核心原理和应用实践/01.html" class="nav-link">
  JS设计模式核心原理和应用实践
</a></li></ul></li><li class="dropdown-item"><h4>
          算法和数据结构
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/算法和数据结构/入门级算法/01.html" class="nav-link">
  入门级算法
</a></li><li class="dropdown-subitem"><a href="/front/算法和数据结构/常见算法/01.html" class="nav-link">
  常见算法
</a></li><li class="dropdown-subitem"><a href="/front/算法和数据结构/常见数据结构/01.html" class="nav-link">
  常见数据结构
</a></li><li class="dropdown-subitem"><a href="/front/算法和数据结构/前端算法与数据结构/01.html" class="nav-link">
  前端算法与数据结构
</a></li></ul></li><li class="dropdown-item"><h4>
          基础必备
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/front/base/html必备/01.html" class="nav-link">
  HTML必备
</a></li><li class="dropdown-subitem"><a href="/front/base/CSS必备/01.html" class="nav-link">
  CSS必备
</a></li><li class="dropdown-subitem"><a href="/front/base/JS基础/01.html" class="nav-link">
  JS基础
</a></li><li class="dropdown-subitem"><a href="/front/base/JS进阶/01.html" class="nav-link">
  JS进阶
</a></li><li class="dropdown-subitem"><a href="/front/base/JS练习/01.html" class="nav-link">
  JS练习
</a></li><li class="dropdown-subitem"><a href="/front/base/网络基础/01.html" class="nav-link">
  网络基础
</a></li><li class="dropdown-subitem"><a href="/books/JS高级程序设计/01.html" class="nav-link">
  JS高级程序设计
</a></li><li class="dropdown-subitem"><a href="/front/base/浏览器相关基础/01.html" class="nav-link">
  浏览器相关基础
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="电子" class="dropdown-title"><span class="title">电子</span> <span class="arrow down"></span></button> <button type="button" aria-label="电子" class="mobile-dropdown-title"><span class="title">电子</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          STM32
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/电子/STM32四轴飞行器/01.html" class="nav-link">
  STM32四轴飞行器
</a></li></ul></li><li class="dropdown-item"><h4>
          Arduino
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/电子/Arduino墙画机/01.html" class="nav-link">
  Arduino墙画机
</a></li><li class="dropdown-subitem"><a href="/电子/Arduino四轴飞行器/01.html" class="nav-link">
  Arduino四轴飞行器
</a></li><li class="dropdown-subitem"><a href="/电子/Arduino四足仿生机器人/01.html" class="nav-link">
  Arduino四足仿生机器人
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="关于" class="dropdown-title"><span class="title">关于</span> <span class="arrow down"></span></button> <button type="button" aria-label="关于" class="mobile-dropdown-title"><span class="title">关于</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/关于我/01.html" class="nav-link">
  关于我
</a></li><li class="dropdown-item"><!----> <a href="https://github.com/fangfeiyue" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Github
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>JS深入</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/front/base/JS深入/01.html" class="sidebar-link">简介</a></li><li><a href="/front/base/JS深入/02.html" class="sidebar-link">JS中的数据类型</a></li><li><a href="/front/base/JS深入/03.html" class="sidebar-link">堆栈内存</a></li><li><a href="/front/base/JS深入/04.html" class="sidebar-link">作用域和作用域链</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/04.html#练习" class="sidebar-link">练习</a></li></ul></li><li><a href="/front/base/JS深入/31.html" class="sidebar-link">JS中this的五种情况</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/31.html#事件绑定" class="sidebar-link">事件绑定</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/31.html#普通函数执行" class="sidebar-link">普通函数执行</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/31.html#构造函数执行" class="sidebar-link">构造函数执行</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/31.html#箭头函数" class="sidebar-link">箭头函数</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/31.html#call、apply、bind" class="sidebar-link">call、apply、bind</a></li></ul></li><li><a href="/front/base/JS深入/32.html" class="sidebar-link">JS中数据类型检测的四种方案</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/32.html#typeof" class="sidebar-link">typeof</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/32.html#instanceof" class="sidebar-link">instanceof</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/32.html#object-prototype-tostring-call" class="sidebar-link">Object.prototype.toString.call</a></li></ul></li><li><a href="/front/base/JS深入/33.html" class="sidebar-link">JS中的继承方案</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/33.html#原型继承" class="sidebar-link">原型继承</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/33.html#call继承" class="sidebar-link">call继承</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/33.html#寄生组合继承" class="sidebar-link">寄生组合继承</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/33.html#class实现继承" class="sidebar-link">class实现继承</a></li></ul></li><li><a href="/front/base/JS深入/35.html" class="sidebar-link">高阶函数</a></li><li><a href="/front/base/JS深入/36.html" class="sidebar-link">发布订阅和观察者模式</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/36.html#发布订阅和观察者模式" class="sidebar-link">发布订阅和观察者模式</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/36.html#观察者模式" class="sidebar-link">观察者模式</a></li></ul></li><li><a href="/front/base/JS深入/37.html" class="active sidebar-link">Promise</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#promise简介" class="sidebar-link">Promise简介</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#手写promise-简单功能" class="sidebar-link">手写Promise(简单功能)</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#手写promise-异步" class="sidebar-link">手写Promise（异步）</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#手写promise-链式调用" class="sidebar-link">手写Promise（链式调用）</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#promise的状态更改问题" class="sidebar-link">promise的状态更改问题</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#延迟对象的作用" class="sidebar-link">延迟对象的作用</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#catch方法的实现" class="sidebar-link">catch方法的实现</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#resolve和reject方法的区别" class="sidebar-link">resolve和reject方法的区别</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#finally的实现原理" class="sidebar-link">finally的实现原理</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#promisify" class="sidebar-link">promisify</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#promise-all" class="sidebar-link">promise-all</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#promise-race" class="sidebar-link">promise-race</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#中断promise链" class="sidebar-link">中断promise链</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/37.html#promise实战" class="sidebar-link">promise实战</a></li></ul></li><li><a href="/front/base/JS深入/39.html" class="sidebar-link">手写常用方法</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手写bind函数" class="sidebar-link">手写bind函数</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手写call函数" class="sidebar-link">手写call函数</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手写apply函数" class="sidebar-link">手写apply函数</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手写防抖函数" class="sidebar-link">手写防抖函数</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手写节流函数" class="sidebar-link">手写节流函数</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#实现js中的深拷贝" class="sidebar-link">实现js中的深拷贝</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#实现柯里化函数" class="sidebar-link">实现柯里化函数</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手写一个观察者模式" class="sidebar-link">手写一个观察者模式</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手动实现eventemitter-发布订阅模式" class="sidebar-link">手动实现EventEmitter(发布订阅模式)</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手动实现jsonp" class="sidebar-link">手动实现jsonp</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手动实现new关键字" class="sidebar-link">手动实现new关键字</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手动实现-object-assign" class="sidebar-link">手动实现 Object.assign</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#实现-解析url参数为对象-的函数" class="sidebar-link">实现 解析url参数为对象 的函数</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#js格式化数字-每三位加逗号" class="sidebar-link">js格式化数字(每三位加逗号)</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手写instanceof关键字" class="sidebar-link">手写instanceof关键字</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/39.html#手写数组去重的方法" class="sidebar-link">手写数组去重的方法</a></li></ul></li><li><a href="/front/base/JS深入/41.html" class="sidebar-link">EventLoop</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/41.html#浏览器的进程" class="sidebar-link">浏览器的进程</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/41.html#渲染进程-包含着多个线程" class="sidebar-link">渲染进程（包含着多个线程）</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/41.html#宏任务-微任务" class="sidebar-link">宏任务,微任务</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/41.html#微任务和gui渲染" class="sidebar-link">微任务和GUI渲染</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/41.html#事件任务" class="sidebar-link">事件任务</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/41.html#定时器任务" class="sidebar-link">定时器任务</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/41.html#实战题" class="sidebar-link">实战题</a></li></ul></li><li><a href="/front/base/JS深入/43.html" class="sidebar-link">跨域</a></li><li><a href="/front/base/JS深入/45.html" class="sidebar-link">JS面试题</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#null是对象吗-为什么" class="sidebar-link">null是对象吗？为什么？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#_1-tostring-为什么可以调用" class="sidebar-link">'1'.toString()为什么可以调用？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#_0-1-0-2为什么不等于0-3" class="sidebar-link">0.1+0.2为什么不等于0.3？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#手动实现一下instanceof的功能" class="sidebar-link">手动实现一下instanceof的功能</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#object-is和-的区别" class="sidebar-link">Object.is和===的区别？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#结果是什么-为什么" class="sidebar-link">[] == ![]结果是什么？为什么？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#js中类型转换有哪几种" class="sidebar-link">JS中类型转换有哪几种？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#和-有什么区别" class="sidebar-link">== 和 ===有什么区别？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#对象转原始类型是根据什么流程运行的" class="sidebar-link">对象转原始类型是根据什么流程运行的？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#如何让if-a-1-a-2-条件成立" class="sidebar-link">如何让if(a == 1 &amp;&amp; a == 2)条件成立？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#谈谈你对闭包的理解" class="sidebar-link">谈谈你对闭包的理解</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#谈谈你对原型链的理解" class="sidebar-link">谈谈你对原型链的理解</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#js如何实现继承" class="sidebar-link">JS如何实现继承</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#textcontent、innertext和innerhtml的用法以及区别" class="sidebar-link">textContent、innerText和innerHTML的用法以及区别</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#js异步编程有哪些方案-为什么会出现这些方案" class="sidebar-link">JS异步编程有哪些方案？为什么会出现这些方案？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#promise-怎么解决回调地狱问题的" class="sidebar-link">Promise 怎么解决回调地狱问题的？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#为什么promise要引入微任务" class="sidebar-link">为什么Promise要引入微任务？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#promise-如何实现链式调用" class="sidebar-link">Promise 如何实现链式调用</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#谈谈你对生成器以及协程的理解" class="sidebar-link">谈谈你对生成器以及协程的理解</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#如何让-generator-的异步代码按顺序执行完毕" class="sidebar-link">如何让 Generator 的异步代码按顺序执行完毕？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#如何让-generator-的异步代码按顺序执行完毕-2" class="sidebar-link">如何让 Generator 的异步代码按顺序执行完毕？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#解释一下async-await的运行机制" class="sidebar-link">解释一下async/await的运行机制</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#foreach-中用-await-会产生什么问题-怎么解决这个问题" class="sidebar-link">forEach 中用 await 会产生什么问题?怎么解决这个问题？</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#iterator" class="sidebar-link">Iterator</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#foreach的使用注意点" class="sidebar-link">forEach的使用注意点</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#javascript-创建对象的几种方式" class="sidebar-link">JavaScript 创建对象的几种方式?</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/45.html#javascript-继承的几种实现方式" class="sidebar-link">JavaScript 继承的几种实现方式?</a></li></ul></li><li><a href="/front/base/JS深入/46.html" class="sidebar-link">跨域</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front/base/JS深入/46.html#遇到的问题" class="sidebar-link">遇到的问题</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/46.html#手写ajax" class="sidebar-link">手写ajax</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/46.html#基于js实现ajax请求并发请求的控制" class="sidebar-link">基于JS实现Ajax请求并发请求的控制</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/46.html#说下vuex" class="sidebar-link">说下vuex</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/46.html#路由懒加载的原理" class="sidebar-link">路由懒加载的原理</a></li><li class="sidebar-sub-header"><a href="/front/base/JS深入/46.html#性能优化-强缓存、协商缓存-字体icon、小图片base64-强缓存返回200-协商304" class="sidebar-link">性能优化，强缓存、协商缓存 字体icon、小图片base64  强缓存返回200 协商304</a></li></ul></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h2 id="promise简介"><a href="#promise简介" class="header-anchor">#</a> Promise简介</h2> <p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank" rel="noopener noreferrer">Promise MDN<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p><a href="https://es6.ruanyifeng.com/#docs/promise" target="_blank" rel="noopener noreferrer">Promise 对象<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p><a href="https://promisesaplus.com/" target="_blank" rel="noopener noreferrer">Promises/A+官方文档<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p>这里简单总结下promise的特点，具体使用方法可以参考上面的资料链接，这里不对promise的基本做讲解。</p> <ol><li><p>promise有三个状态：成功态(resolve)、失败态(reject)、等待态(pending)</p></li> <li><p>promise默认执行器是立即执行，下面的函数输出1、2</p></li></ol> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> promise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span>

<span class="token comment">/* 
输出结果
1
2
*/</span>
</code></pre></div><ol start="3"><li><p>用户自己决定失败的原因和成功的原因  成功和失败也是用户定义的</p></li> <li><p>promise的实例都拥有一个then方法 , 一个参数是成功的回调，另一个失败的回调</p></li> <li><p>如果执行函数时发生了异常也会执行失败逻辑</p></li> <li><p>如果promise一旦成功就不能失败 ， 反过来也是一样的 (只有等待态的时候才能去更改状态)</p></li></ol> <p>以上是我们对promise的一些特性总结，下面我们自己来写个简单的promise</p> <p>看看以下输出结果是什么呢：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 第一题</span>
<span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">reject</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">_</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'ok'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token parameter">_</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'fail'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token comment">// 第二题</span>
<span class="token keyword">const</span> promise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span>reject</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">// 第三题</span>
Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span><span class="token number">2</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token operator">=&gt;</span><span class="token number">3</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 第四题</span>
Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token operator">=&gt;</span>x<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span><span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'My Error'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token operator">=&gt;</span>x<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>error<span class="token punctuation">)</span>
</code></pre></div><p>输出结果依次为</p> <div class="language- extra-class"><pre class="language-text"><code>第一题 fail
第二题 1、2、3
第三题 2
第四题 2
</code></pre></div><h2 id="手写promise-简单功能"><a href="#手写promise-简单功能" class="header-anchor">#</a> 手写Promise(简单功能)</h2> <p>上面我们已经总结出了Promise的几个特点，并且借助<a href="https://promisesaplus.com/" target="_blank" rel="noopener noreferrer">Promises/A+官方文档<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>我们可以尝试写个自己的Promise玩玩</p> <p>回想下自调用自带的Promise的写法</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token parameter">err</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>从上面的代码中可以看出Promise是个类，且在创建的时候传递了一个函数做为参数，传递的这个函数接收两个方法做为参数来改变Promise的状态，new出来的实例可以调用then方法，then方法也接收两个参数，由此可知我们创建的Promise首先得是个类，构造函数的参数得接收一个方法做为参数，且这个方法要立即执行，生成的实例可以调用then方法等等</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// promise的三个状态</span>
<span class="token keyword">const</span> <span class="token constant">PENDING</span> <span class="token operator">=</span> <span class="token string">'PENDING'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">REJECTED</span> <span class="token operator">=</span> <span class="token string">'REJECTED'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">FULFILLED</span> <span class="token operator">=</span> <span class="token string">'FULFILLED'</span><span class="token punctuation">;</span>

<span class="token keyword">class</span> <span class="token class-name">PromiseA</span> <span class="token punctuation">{</span>
  <span class="token comment">// executor，构造函数参数，执行器</span>
	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">executor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// promise的状态，默认为PENDING</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">PENDING</span><span class="token punctuation">;</span>
    <span class="token comment">// 成功的值</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>
    <span class="token comment">// 失败的原因</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>

		<span class="token keyword">const</span> <span class="token function-variable function">resolve</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// 状态为PENDING时状态才可以改变</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">FULFILLED</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>
		<span class="token keyword">const</span> <span class="token function-variable function">reject</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// 状态为PENDING时状态才可以改变</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> reason<span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">REJECTED</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>

		<span class="token keyword">try</span> <span class="token punctuation">{</span>
			<span class="token function">executor</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 失败</span>
			<span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// promise的then方法</span>
	<span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">onFulfilled<span class="token punctuation">,</span> onRejected</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 状态为FULFILLED</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">FULFILLED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token function">onFulfilled</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 状态为REJECTED</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">REJECTED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token function">onRejected</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> PromiseA<span class="token punctuation">;</span>
</code></pre></div><p>测试是否成功：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 因为自己写的文件</span>
<span class="token keyword">const</span> PromiseA <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./p1'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> promise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PromiseA</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// resolve('ok')</span>
  <span class="token function">reject</span><span class="token punctuation">(</span><span class="token string">'fail'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// 输出</span>
<span class="token comment">// ok</span>
<span class="token comment">// fail</span>
</code></pre></div><h2 id="手写promise-异步"><a href="#手写promise-异步" class="header-anchor">#</a> 手写Promise（异步）</h2> <p>上面我们实现了一个简版的promise，并且通过简单的实例测试了是否可用，但是这还差的远，以上只是实现了promise最基本的用法，我们使用promise一般是为了处理异步问题，上面的写法显然还处理不了异步问题，因为可能在调用then方法的时候promise的状态还是pending状态，在咱们自己的promise中then方法我们只处理了成功和失败</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> PromiseA <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./p1'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> promise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PromiseA</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'ok'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>上述代码理论上一秒钟后应该输出ok，但实际上并未得到我们想要的结果，下面我们来解决这个问题。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// promise的三个状态</span>
<span class="token keyword">const</span> <span class="token constant">PENDING</span> <span class="token operator">=</span> <span class="token string">'PENDING'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">REJECTED</span> <span class="token operator">=</span> <span class="token string">'REJECTED'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">FULFILLED</span> <span class="token operator">=</span> <span class="token string">'FULFILLED'</span><span class="token punctuation">;</span>

<span class="token keyword">class</span> <span class="token class-name">PromiseA</span> <span class="token punctuation">{</span>
  <span class="token comment">// executor，构造函数参数，执行器</span>
	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">executor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// promise的状态，默认为PENDING</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">PENDING</span><span class="token punctuation">;</span>
    <span class="token comment">// 成功的值</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>
    <span class="token comment">// 失败的原因</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>

    <span class="token comment">// 成功和失败的回调之所以用数组存放是因为then方法可以被调用多次，如果then被调用多次后promise的状态依然为pending状态，then里面的成功和失败方法应被暂存起来，等到promise状态变化后依次执行</span>
		<span class="token comment">// 存放成功的回调</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
		<span class="token comment">// 存放失败的回调</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

		<span class="token keyword">const</span> <span class="token function-variable function">resolve</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// 状态为PENDING时状态才可以改变</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">FULFILLED</span><span class="token punctuation">;</span>
        <span class="token comment">// 当状态变为FULFILLED，依次执行成功的方法</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>
		<span class="token keyword">const</span> <span class="token function-variable function">reject</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// 状态为PENDING时状态才可以改变</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> reason<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">REJECTED</span><span class="token punctuation">;</span>
        <span class="token comment">// 当状态变为REJECTED，依次执行失败的方法</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>

		<span class="token keyword">try</span> <span class="token punctuation">{</span>
			<span class="token function">executor</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 失败</span>
			<span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
	<span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">onFulfilled<span class="token punctuation">,</span> onRejected</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">FULFILLED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token function">onFulfilled</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">REJECTED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token function">onRejected</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 当调用then方法的时候状态为PENDING状态，先将成功和失败的方法暂时存放起来，等到状态改变后依次调用</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
				<span class="token function">onFulfilled</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
				<span class="token function">onRejected</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> PromiseA<span class="token punctuation">;</span>
</code></pre></div><p>测试所写功能是否生效</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> PromiseA <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./p1'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> promise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PromiseA</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'ok'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>一秒钟后成功输出了ok</p> <h2 id="手写promise-链式调用"><a href="#手写promise-链式调用" class="header-anchor">#</a> 手写Promise（链式调用）</h2> <p>异步方法无法通过try...catch捕获错误</p> <p>上面我们实现了promise最基本的功能和处理异步的功能，但是有事我们会向下面这样使用promise</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> p2 <span class="token operator">=</span> p1<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token comment">// 100</span>
  <span class="token keyword">return</span> <span class="token number">200</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> p3 <span class="token operator">=</span> p2<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token comment">// 200</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> p4 <span class="token operator">=</span> p3<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
  <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'err'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
p4<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'ok'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'err'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// err</span>
</code></pre></div><p>上面写的代码没法实现这种链式调用，下面咱们来实现链式调用功能。写之前咱们还是先分析下p2为什么可以调用then方法，只有可能p2也是Promise的实例才可以调用then方法，那它是不是当前的promise实例呢？</p> <p>显然不是，因为p1已经成功了状态不能再改变，但当p3抛出错误后，依然会被捕获到错误，p3的状态还是可变的，所以分析得p3是一个新的promise，而且是当p1调用then方法后返回的一个promise。</p> <p>调用p2的then方法，输出p1.then方法中返回的200，这个是怎么做到的呢？我们知道p1的then方法能输出100是因为调用了resolve方法，所以只要调用p2的resolve方法就可以拿到200了</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token constant">PENDING</span> <span class="token operator">=</span> <span class="token string">'PENDING'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">REJECTED</span> <span class="token operator">=</span> <span class="token string">'REJECTED'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">FULFILLED</span> <span class="token operator">=</span> <span class="token string">'FULFILLED'</span><span class="token punctuation">;</span>

<span class="token keyword">class</span> <span class="token class-name">PromiseA</span> <span class="token punctuation">{</span>
	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">executor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">PENDING</span><span class="token punctuation">;</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>

		<span class="token comment">// 存放成功的回调</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
		<span class="token comment">// 存放失败的回调</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

		<span class="token keyword">const</span> <span class="token function-variable function">resolve</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">FULFILLED</span><span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>
		<span class="token keyword">const</span> <span class="token function-variable function">reject</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> reason<span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">REJECTED</span><span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>

		<span class="token keyword">try</span> <span class="token punctuation">{</span>
			<span class="token function">executor</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 1. promise 成功和失败的回调的返回值 可以传递到外层的下一个then</span>
  <span class="token comment">// 2. 如果返回的是普通值的话 (传递到下一次的成功中,不是错误不是promise就是普通值) ，出错的情况(一定会走到下一次的失败),可能还要promise的情况(会采用promise的状态，决定走下一次的成功还是失败 )</span>
  <span class="token comment">// 3. 错误处理 如果离自己最近的then 没有错误处理(没有写错误函数) 会向下找</span>
  <span class="token comment">// 4. 每次执行完promise.then方法后返回的都是一个“新的promise&quot; (promisey一旦成功或者失败就不能修改状态)</span>
	<span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">onFulfilled<span class="token punctuation">,</span> onRejected</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 为了实现链式调用，每次执行完promise.then方法后返回的都是一个“新的promise&quot; (因为promisey一旦成功或者失败就不能修改状态，所以不能返回this)</span>
    <span class="token keyword">const</span> promise2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">FULFILLED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onFulfilled</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span>
        <span class="token function">resolve</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">REJECTED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onRejected</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 如果失败的话，失败的返回值要传到下一个promise的的成功中</span>
        <span class="token function">resolve</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onFulfilled</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token function">resolve</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  
        <span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onRejected</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token function">resolve</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> promise2
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> PromiseA<span class="token punctuation">;</span>
</code></pre></div><p>正常情况下我们会向下面这样使用promise</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 伪代码获取新闻详情内容和推荐列表</span>
<span class="token keyword">function</span> <span class="token function">getNewsDetail</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'ok'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token function">getNewsDetail</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
  <span class="token comment">// 假设先获取新闻详情内容id，通过内容id获取相关的新闻</span>
  <span class="token keyword">return</span> <span class="token function">fetchList</span><span class="token punctuation">(</span>res<span class="token punctuation">.</span>id<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// TODO</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>返回的不再是个普通值而是promise的情况，我们改怎么办呢？promise2状态的处理、promise2和x引用同一变量</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token constant">PENDING</span> <span class="token operator">=</span> <span class="token string">'PENDING'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">REJECTED</span> <span class="token operator">=</span> <span class="token string">'REJECTED'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">FULFILLED</span> <span class="token operator">=</span> <span class="token string">'FULFILLED'</span><span class="token punctuation">;</span>

<span class="token comment">// x决定p2是成功还是失败</span>
<span class="token keyword">function</span> <span class="token function">resolvePromise</span><span class="token punctuation">(</span><span class="token parameter">promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// console.log('promise2',promise2, 'x',x, 'resolve',resolve, 'reject',reject)</span>

  <span class="token comment">// 循环引用，自己等待自己完成，错误的实现用于解决下面这种问题</span>
  <span class="token comment">/* 
  const p = new Promise((resolve, reject) =&gt; {
    resolve(100)
  })

  const p2 = p.then(_=&gt;p2)
  p2.then(res=&gt;console.log('res', res), err=&gt;console.log('err', err))
  */</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>promise2 <span class="token operator">===</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 用一个类型错误结束调promise </span>
    <span class="token function">reject</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TypeError</span><span class="token punctuation">(</span><span class="token string">'Chaining cycle detected for promise'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token comment">// 后续的代码要严格判断，保证代码能和别的库一起使用如bluebird、es6-promise</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">class</span> <span class="token class-name">PromiseA</span> <span class="token punctuation">{</span>
	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">executor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">PENDING</span><span class="token punctuation">;</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>

		<span class="token comment">// 存放成功的回调</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
		<span class="token comment">// 存放失败的回调</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

		<span class="token keyword">const</span> <span class="token function-variable function">resolve</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">FULFILLED</span><span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>
		<span class="token keyword">const</span> <span class="token function-variable function">reject</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> reason<span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">REJECTED</span><span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>

		<span class="token keyword">try</span> <span class="token punctuation">{</span>
			<span class="token function">executor</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 1. promise 成功和失败的回调的返回值 可以传递到外层的下一个then</span>
  <span class="token comment">// 2. 如果返回的是普通值的话 (传递到下一次的成功中,不是错误不是promise就是普通值) ，出错的情况(一定会走到下一次的失败),可能还要promise的情况(会采用promise的状态，决定走下一次的成功还是失败 )</span>
  <span class="token comment">// 3. 错误处理 如果离自己最近的then 没有错误处理(没有写错误函数) 会向下找</span>
  <span class="token comment">// 4. 每次执行完promise.then方法后返回的都是一个“新的promise&quot; (promisey一旦成功或者失败就不能修改状态)</span>
	<span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">onFulfilled<span class="token punctuation">,</span> onRejected</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 为了实现链式调用，每次执行完promise.then方法后返回的都是一个“新的promise&quot; (因为promisey一旦成功或者失败就不能修改状态，所以不能返回this)</span>
    <span class="token keyword">const</span> promise2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PromiseA</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">FULFILLED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// const x = onFulfilled(this.value)</span>
        <span class="token comment">//  直接这样取拿不到promise2，因为new PromiseA()内部代码还没执行完，拿不到promise2，需要使用定时器</span>
        <span class="token comment">// resolvePromise(promise2, x, resolve, reject)</span>


        <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token comment">// 因为异步调用了onFulfilled，如果发生错误try...catch捕获不到，需要再写一个try...catch</span>
          <span class="token keyword">try</span><span class="token punctuation">{</span>
            <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onFulfilled</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span>
            <span class="token function">resolvePromise</span><span class="token punctuation">(</span>promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
          <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">REJECTED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// const x = onRejected(this.reason);</span>
        <span class="token comment">// 如果失败的话，失败的返回值要传到下一个promise的的成功中</span>
        <span class="token comment">// resolve(x)</span>

        <span class="token comment">// resolvePromise(promise2, x, resolve, reject)</span>
        

        <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">try</span><span class="token punctuation">{</span>
            <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onRejected</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token function">resolvePromise</span><span class="token punctuation">(</span>promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
          <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token comment">// const x = onFulfilled(this.value);</span>
          <span class="token comment">// resolve(x)</span>
          <span class="token comment">// resolvePromise(promise2, x, resolve, reject)</span>
          
          <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">try</span><span class="token punctuation">{</span>
              <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onFulfilled</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
              <span class="token function">resolvePromise</span><span class="token punctuation">(</span>promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
              <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  
        <span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token comment">// const x = onRejected(this.reason);</span>
          <span class="token comment">// resolve(x)</span>
          <span class="token comment">// resolvePromise(promise2, x, resolve, reject)</span>
          
          <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">try</span><span class="token punctuation">{</span>
              <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onRejected</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
              <span class="token function">resolvePromise</span><span class="token punctuation">(</span>promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">{</span>
              <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> promise2
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> PromiseA<span class="token punctuation">;</span>
</code></pre></div><h2 id="promise的状态更改问题"><a href="#promise的状态更改问题" class="header-anchor">#</a> promise的状态更改问题</h2> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token constant">PENDING</span> <span class="token operator">=</span> <span class="token string">'PENDING'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">REJECTED</span> <span class="token operator">=</span> <span class="token string">'REJECTED'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">FULFILLED</span> <span class="token operator">=</span> <span class="token string">'FULFILLED'</span><span class="token punctuation">;</span>

<span class="token comment">// x决定p2是成功还是失败，这块主要还是为了处理返回的是promise问题</span>
<span class="token comment">/* 
const p = new Promise((resolve, reject) =&gt; {
  resolve(100)
})

const p2 = p.then(()=&gt;{
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      reject('err')
    }, 2000);
  })
})

p2.then(data =&gt; console.log('data', data), err =&gt; console.log('fail', err))
*/</span>
<span class="token keyword">function</span> <span class="token function">resolvePromise</span><span class="token punctuation">(</span><span class="token parameter">promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// console.log('promise2',promise2, 'x',x, 'resolve',resolve, 'reject',reject)</span>

  <span class="token comment">// 循环引用，自己等待自己完成，错误的实现用于解决下面这种问题</span>
  <span class="token comment">/* 
  const p = new Promise((resolve, reject) =&gt; {
    resolve(100)
  })

  const p2 = p.then(_=&gt;p2)
  p2.then(res=&gt;console.log('res', res), err=&gt;console.log('err', err))
  */</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>promise2 <span class="token operator">===</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 用一个类型错误结束调promise </span>
    <span class="token function">reject</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TypeError</span><span class="token punctuation">(</span><span class="token string">'Chaining cycle detected for promise'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token comment">// 后续的代码要严格判断，保证代码能和别的库一起使用如bluebird、es6-promise</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">let</span> called
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> x <span class="token operator">===</span> <span class="token string">'object'</span> <span class="token operator">&amp;&amp;</span> x <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token keyword">typeof</span> x <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 有可能是一个promise</span>

    <span class="token keyword">try</span><span class="token punctuation">{</span>
      <span class="token keyword">const</span> then <span class="token operator">=</span> x<span class="token punctuation">.</span>then
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> then <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 只能认为是promise了</span>
        <span class="token comment">// 不要写成x.then 直接then.call就可以了，因为x.then会再次取值，有可能会报错</span>
        <span class="token function">then</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span> <span class="token comment">// 根据promise的状态决定成功还是失败</span>
          x<span class="token punctuation">,</span>
          <span class="token parameter">y</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token comment">// resolve(y)</span>

            <span class="token comment">// 解决问题：</span>
            <span class="token comment">/* 
            const p = new Promise((resolve, reject) =&gt; {
              resolve(100)
            })

            const p2 = p.then(()=&gt;{
              return new Promise((resolve, reject) =&gt; {
                setTimeout(() =&gt; {
                  resolve(new Promise((resolve, reject) =&gt; {
                    setTimeout(() =&gt; {
                      resolve('ok')
                    }, 2000);
                  }))
                }, 2000);
              })
            })

            p2.then(data =&gt; console.log('data', data), err =&gt; console.log('fail', err))
            */</span>

            <span class="token comment">// resolvePromise(promise2, y, resolve, reject) //递归解析过程</span>
            
            
            <span class="token keyword">if</span> <span class="token punctuation">(</span>called<span class="token punctuation">)</span><span class="token keyword">return</span>
            called <span class="token operator">=</span> <span class="token boolean">true</span>
            <span class="token function">resolvePromise</span><span class="token punctuation">(</span>promise2<span class="token punctuation">,</span> y<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span> <span class="token comment">//递归解析过程</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token parameter">r</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>called<span class="token punctuation">)</span><span class="token keyword">return</span>
            called <span class="token operator">=</span> <span class="token boolean">true</span>
            <span class="token function">reject</span><span class="token punctuation">(</span>r<span class="token punctuation">)</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">)</span>
      <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token function">resolve</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">{</span>
      <span class="token comment">// 防止失败了再走成功，主要为了防止调用的其他库的promise走了成功还走失败</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>called<span class="token punctuation">)</span><span class="token keyword">return</span>
      called <span class="token operator">=</span> <span class="token boolean">true</span>
      <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token comment">// 取值出错</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">class</span> <span class="token class-name">Promise</span> <span class="token punctuation">{</span>
	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">executor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">PENDING</span><span class="token punctuation">;</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>

		<span class="token comment">// 存放成功的回调</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
		<span class="token comment">// 存放失败的回调</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

		<span class="token keyword">const</span> <span class="token function-variable function">resolve</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">FULFILLED</span><span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>
		<span class="token keyword">const</span> <span class="token function-variable function">reject</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>reason <span class="token operator">=</span> reason<span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">REJECTED</span><span class="token punctuation">;</span>
				<span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>

		<span class="token keyword">try</span> <span class="token punctuation">{</span>
			<span class="token function">executor</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 1. promise 成功和失败的回调的返回值 可以传递到外层的下一个then</span>
  <span class="token comment">// 2. 如果返回的是普通值的话 (传递到下一次的成功中,不是错误不是promise就是普通值) ，出错的情况(一定会走到下一次的失败),可能还要promise的情况(会采用promise的状态，决定走下一次的成功还是失败 )</span>
  <span class="token comment">// 3. 错误处理 如果离自己最近的then 没有错误处理(没有写错误函数) 会向下找</span>
  <span class="token comment">// 4. 每次执行完promise.then方法后返回的都是一个“新的promise&quot; (promisey一旦成功或者失败就不能修改状态)</span>
	<span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">onFulfilled<span class="token punctuation">,</span> onRejected</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">/*
    const p = new Promise((resolve, reject) =&gt; {
      resolve(1)  
    })

    // 值的穿透
    p.then().then().then(res=&gt;console.log('res===&gt;&gt;', res), err=&gt;console.log('err', err)) // 1
    */</span>
    onFulfilled <span class="token operator">=</span> <span class="token keyword">typeof</span> onFulfilled <span class="token operator">===</span> <span class="token string">'function'</span> <span class="token operator">?</span> <span class="token function-variable function">onFulfilled</span> <span class="token operator">:</span> <span class="token parameter">v</span><span class="token operator">=&gt;</span>v
    onRejected <span class="token operator">=</span> <span class="token keyword">typeof</span> onRejected <span class="token operator">===</span> <span class="token string">'function'</span> <span class="token operator">?</span> <span class="token function-variable function">onRejected</span> <span class="token operator">:</span> <span class="token parameter">err</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span><span class="token keyword">throw</span> err<span class="token punctuation">}</span>


    <span class="token comment">// 为了实现链式调用，每次执行完promise.then方法后返回的都是一个“新的promise&quot; (因为promisey一旦成功或者失败就不能修改状态，所以不能返回this)</span>
    <span class="token keyword">const</span> promise2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">FULFILLED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// const x = onFulfilled(this.value)</span>
        <span class="token comment">//  直接这样取拿不到promise2，因为new Promise()内部代码还没执行完，拿不到promise2，需要使用定时器</span>
        <span class="token comment">// resolvePromise(promise2, x, resolve, reject)</span>


        <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token comment">// 因为异步调用了onFulfilled，如果发生错误try...catch捕获不到，需要再写一个try...catch</span>
          <span class="token keyword">try</span><span class="token punctuation">{</span>
            <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onFulfilled</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span>
            <span class="token function">resolvePromise</span><span class="token punctuation">(</span>promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
          <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">REJECTED</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// const x = onRejected(this.reason);</span>
        <span class="token comment">// 如果失败的话，失败的返回值要传到下一个promise的的成功中</span>
        <span class="token comment">// resolve(x)</span>

        <span class="token comment">// resolvePromise(promise2, x, resolve, reject)</span>
        

        <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">try</span><span class="token punctuation">{</span>
            <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onRejected</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token function">resolvePromise</span><span class="token punctuation">(</span>promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
          <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token comment">// const x = onFulfilled(this.value);</span>
          <span class="token comment">// resolve(x)</span>
          <span class="token comment">// resolvePromise(promise2, x, resolve, reject)</span>
          
          <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">try</span><span class="token punctuation">{</span>
              <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onFulfilled</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
              <span class="token function">resolvePromise</span><span class="token punctuation">(</span>promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
              <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  
        <span class="token keyword">this</span><span class="token punctuation">.</span>onRejectedCallBacks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token comment">// const x = onRejected(this.reason);</span>
          <span class="token comment">// resolve(x)</span>
          <span class="token comment">// resolvePromise(promise2, x, resolve, reject)</span>
          
          <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">try</span><span class="token punctuation">{</span>
              <span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">onRejected</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
              <span class="token function">resolvePromise</span><span class="token punctuation">(</span>promise2<span class="token punctuation">,</span> x<span class="token punctuation">,</span> resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">{</span>
              <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> promise2
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// 规范测试</span>
Promise<span class="token punctuation">.</span>defer <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function-variable function">deferred</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> dfd <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  dfd<span class="token punctuation">.</span>promise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      dfd<span class="token punctuation">.</span>resolve <span class="token operator">=</span> resolve
      dfd<span class="token punctuation">.</span>reject <span class="token operator">=</span> reject
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span> dfd
<span class="token punctuation">}</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> Promise<span class="token punctuation">;</span>
</code></pre></div><p>安装<code>promises-aplus-tests</code></p> <div class="language-js extra-class"><pre class="language-js"><code>npm install promises<span class="token operator">-</span>aplus<span class="token operator">-</span>tests <span class="token operator">-</span><span class="token constant">D</span>
</code></pre></div><p>终端执行</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// promise.js文件是自己写的promise代码</span>
npx promises<span class="token operator">-</span>aplus<span class="token operator">-</span>tests promise<span class="token punctuation">.</span>js
</code></pre></div><p>如果输出没有错误说明检查通过，所写代码符合promise规范</p> <h2 id="延迟对象的作用"><a href="#延迟对象的作用" class="header-anchor">#</a> 延迟对象的作用</h2> <p>上述代码中这块代码有什么用呢？</p> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span>defer <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function-variable function">deferred</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> dfd <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  dfd<span class="token punctuation">.</span>promise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      dfd<span class="token punctuation">.</span>resolve <span class="token operator">=</span> resolve
      dfd<span class="token punctuation">.</span>reject <span class="token operator">=</span> reject
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span> dfd 
<span class="token punctuation">}</span>
</code></pre></div><p>延迟对象的作用</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> Promise <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./p7'</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function">readFile</span><span class="token punctuation">(</span><span class="token parameter">fileName</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    fs<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span>fileName<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
        <span class="token keyword">return</span>
      <span class="token punctuation">}</span>
      <span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

  <span class="token keyword">return</span> dfd<span class="token punctuation">.</span>promise
<span class="token punctuation">}</span>
<span class="token function">readFile</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span><span class="token string">'11.js'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'err'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>上述代码我们给fs.readFile包了异常Promise，如果感觉不好看，可
以用延迟对象</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> Promise <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./p7'</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function">readFile</span><span class="token punctuation">(</span><span class="token parameter">fileName</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token keyword">let</span> dfd <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">defer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  fs<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span>fileName<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> dfd<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
    dfd<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

  <span class="token keyword">return</span> dfd<span class="token punctuation">.</span>promise
<span class="token punctuation">}</span>
<span class="token function">readFile</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span><span class="token string">'11.js'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'err'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><h2 id="catch方法的实现"><a href="#catch方法的实现" class="header-anchor">#</a> catch方法的实现</h2> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">reject</span><span class="token punctuation">(</span><span class="token string">'err'</span><span class="token punctuation">)</span>  
<span class="token punctuation">}</span><span class="token punctuation">)</span>

p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'err'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>我们可以借助then方法来实现catch方法，上述代码捕获错误我们用的是then方法，假设我们给then方法的第一参数传null，然后返回这个then方法是不是可以呢</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Promise</span> <span class="token punctuation">{</span>
  <span class="token operator">...</span> 
  <span class="token function">catch</span><span class="token punctuation">(</span>cb<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> cb<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="resolve和reject方法的区别"><a href="#resolve和reject方法的区别" class="header-anchor">#</a> resolve和reject方法的区别</h2> <p>解决这种问题</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span>
p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>代码</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Promise</span> <span class="token punctuation">{</span>
  <span class="token operator">...</span> 
  <span class="token keyword">static</span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">static</span> <span class="token function">reject</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token function">reject</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre></div><p>这种问题的话上面的代码解决不了</p> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'ok'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">data</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>应该输出ok但使用咱们自己的写的promise输出的是是一个promise对象，怎么解决这个这个问题？</p> <p>要想解决这个问题，首先得分析下原因，为啥会输出一个promise对象呢？</p> <p>是因为将一个new Promise(...)当成了一个参数，传给了咱们自己写的Promise的静态方法resolve</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">static</span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div><p>这个方法又调用了咱们源码中写的resolve方法</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token function-variable function">resolve</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">FULFILLED</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>将new Promise(...)传递给了value</p> <p>改为</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token function-variable function">resolve</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// 判断value是不是promise</span>
<span class="token operator">+</span>  <span class="token keyword">if</span><span class="token punctuation">(</span>value <span class="token keyword">instanceof</span> <span class="token class-name">Promise</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 递归解析直到value是给普通值</span>
<span class="token operator">+</span>    <span class="token keyword">return</span> value<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
<span class="token operator">+</span>  <span class="token punctuation">}</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">PENDING</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">FULFILLED</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>onResolvedCallBacks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>resolve会等待里面的promise执行完毕，reject不会等待</p> <h2 id="finally的实现原理"><a href="#finally的实现原理" class="header-anchor">#</a> finally的实现原理</h2> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'ok'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">finally</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'1000'</span><span class="token punctuation">)</span>
      <span class="token comment">// reject('err')</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'err'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>finally 无论如何都会执行，如果finally返回的是一个promise，会等待这个promise执行完，如果是失败的promise会用它失败的原因传给下一个promise</p> <p>我们来实现finally方法</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Promise</span> <span class="token punctuation">{</span>
  <span class="token operator">...</span>
  <span class="token function">finally</span> <span class="token punctuation">(</span>cb<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token function">cb</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span> <span class="token operator">=&gt;</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token function">cb</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre></div><p>调用</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> Promise <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./promise'</span><span class="token punctuation">)</span>
Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">finally</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span><span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// 这样会有问题，日志输出了1000，应该输出100</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'err'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>将finally做如下修改</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Promise</span> <span class="token punctuation">{</span>
  <span class="token operator">...</span>
  <span class="token function">finally</span> <span class="token punctuation">(</span>cb<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">value</span> <span class="token operator">=&gt;</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token function">cb</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">_</span><span class="token operator">=&gt;</span>value<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">reason</span> <span class="token operator">=&gt;</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token function">cb</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">_</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span><span class="token keyword">throw</span> reason<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="promisify"><a href="#promisify" class="header-anchor">#</a> promisify</h2> <p>将node api快速转换成promise方法</p> <p>举例：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>promises
</code></pre></div><p>promises是一个实验性的语法，可以使用</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> util <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'util'</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> readFile <span class="token operator">=</span> util<span class="token punctuation">.</span><span class="token function">promisify</span><span class="token punctuation">(</span>fs<span class="token punctuation">.</span>readFile<span class="token punctuation">)</span>

<span class="token function">readFile</span><span class="token punctuation">(</span><span class="token string">'a.txt'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>promisify是怎么实现的呢</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token function-variable function">promisify</span> <span class="token operator">=</span> <span class="token parameter">fn</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">fn</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><h2 id="promise-all"><a href="#promise-all" class="header-anchor">#</a> promise-all</h2> <p>代码实现</p> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function-variable function">all</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">promises</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
    <span class="token keyword">let</span> count <span class="token operator">=</span> <span class="token number">0</span>
    <span class="token keyword">const</span> <span class="token function-variable function">handleData</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">index<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      arr<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token operator">=</span> data 
      
      <span class="token comment">// 不能使用数组的长度来计算，下面这样写会出错</span>
      <span class="token comment">// if (arr.length === promises.length) {</span>
      <span class="token comment">//   resolve(arr)</span>
      <span class="token comment">// }</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span>count <span class="token operator">===</span> promises<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">resolve</span><span class="token punctuation">(</span>arr<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">const</span> <span class="token function-variable function">isPromise</span> <span class="token operator">=</span> <span class="token parameter">val</span> <span class="token operator">=&gt;</span> <span class="token keyword">typeof</span> val<span class="token punctuation">.</span>then <span class="token operator">===</span> <span class="token string">'function'</span>

    promises <span class="token operator">&amp;&amp;</span> promises<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">promise<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isPromise</span><span class="token punctuation">(</span>promise<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token function">handleData</span><span class="token punctuation">(</span>index<span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
      <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token function">handleData</span><span class="token punctuation">(</span>index<span class="token punctuation">,</span> promise<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token comment">//测试</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> Promise <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./promise'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>promises

Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">[</span>fs<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'11.js'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> fs<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'11.js'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><h2 id="promise-race"><a href="#promise-race" class="header-anchor">#</a> promise-race</h2> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function-variable function">race</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">promises</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token function-variable function">isPromise</span> <span class="token operator">=</span> <span class="token parameter">val</span> <span class="token operator">=&gt;</span> <span class="token keyword">typeof</span> val<span class="token punctuation">.</span>then <span class="token operator">===</span> <span class="token string">'function'</span>

    promises <span class="token operator">&amp;&amp;</span> promises<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">promise</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isPromise</span><span class="token punctuation">(</span>promise<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
      <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token function">resolve</span><span class="token punctuation">(</span>promise<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="中断promise链"><a href="#中断promise链" class="header-anchor">#</a> 中断promise链</h2> <p>需求：一个promise正在走向成功，如果超过2s就认为失败了</p> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function-variable function">race</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">promises</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token function-variable function">isPromise</span> <span class="token operator">=</span> <span class="token parameter">val</span> <span class="token operator">=&gt;</span> <span class="token keyword">typeof</span> val<span class="token punctuation">.</span>then <span class="token operator">===</span> <span class="token string">'function'</span>

    promises <span class="token operator">&amp;&amp;</span> promises<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">promise</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isPromise</span><span class="token punctuation">(</span>promise<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
      <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token function">resolve</span><span class="token punctuation">(</span>promise<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> <span class="token function-variable function">wrap</span> <span class="token operator">=</span> <span class="token parameter">promise</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> abort
  <span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    abort <span class="token operator">=</span> reject
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> p1 <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">race</span><span class="token punctuation">(</span><span class="token punctuation">[</span>promise<span class="token punctuation">,</span> p<span class="token punctuation">]</span><span class="token punctuation">)</span>
  p1<span class="token punctuation">.</span>abort <span class="token operator">=</span> abort
  <span class="token keyword">return</span> p1
<span class="token punctuation">}</span>

<span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'接口请求成功'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> p1 <span class="token operator">=</span> <span class="token function">wrap</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span>
<span class="token keyword">const</span> p2 <span class="token operator">=</span> p1<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'err'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  p1<span class="token punctuation">.</span><span class="token function">abort</span><span class="token punctuation">(</span><span class="token string">'请求超时'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>中断promise链</p> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token operator">=&gt;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res===&gt;&gt;'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><h3 id="generator"><a href="#generator" class="header-anchor">#</a> generator</h3> <p>generator生成器 =》 遍历器（需要一个next方法） 数组 =》 类数组（长的像数组）</p> <p>generator函数是es6语法，如果碰到yield会暂停执行</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token operator">*</span> <span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">yield</span> <span class="token number">1</span>
  <span class="token keyword">yield</span> <span class="token number">2</span>
  <span class="token keyword">yield</span> <span class="token number">3</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> it <span class="token operator">=</span> <span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment">// console.log(it.next())</span>
<span class="token comment">// console.log(it.next())</span>
<span class="token comment">// console.log(it.next())</span>
  
<span class="token keyword">let</span> flag <span class="token operator">=</span> <span class="token boolean">false</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>flag<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> value<span class="token punctuation">,</span> done <span class="token punctuation">}</span> <span class="token operator">=</span> it<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  flag <span class="token operator">=</span> done
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>初步使用，执行顺序</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token operator">*</span> <span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token keyword">yield</span> <span class="token number">1</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">,</span> a<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> b <span class="token operator">=</span> <span class="token keyword">yield</span> <span class="token number">2</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> c <span class="token operator">=</span> <span class="token keyword">yield</span> <span class="token number">3</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'c'</span><span class="token punctuation">,</span> c<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> c
<span class="token punctuation">}</span>
<span class="token comment">// 蛇形执行，除了第一次执行的next方法，都是把next中的参数传递给上一次的yield返回结果</span>
<span class="token keyword">const</span> it <span class="token operator">=</span> <span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
it<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 第一次的next传递参数没有任何意义</span>
it<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token string">'2'</span><span class="token punctuation">)</span>
it<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token string">'3'</span><span class="token punctuation">)</span>
it<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token string">'4'</span><span class="token punctuation">)</span>
</code></pre></div><p><code>[...arr]</code>原理就是遍历这个对象，将结果放到数组中，这个数据必须得有个遍历器</p> <p>将类数组转化为数组的两种方式：</p> <ol><li>Array.from</li></ol> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> likeArray <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token number">0</span><span class="token operator">:</span> <span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token operator">:</span> <span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token operator">:</span> <span class="token string">'c'</span><span class="token punctuation">,</span> length<span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>likeArray<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [ 'a', 'b', 'c' ]</span>

<span class="token comment">// 使用Array.from转换数组时不能类数组必须有length属性，否则会返回空数组</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token operator">:</span> <span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token operator">:</span> <span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token operator">:</span> <span class="token string">'c'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// []</span>
</code></pre></div><ol start="2"><li>遍历器</li></ol> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> likeArray <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token number">0</span><span class="token operator">:</span> <span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token operator">:</span> <span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token operator">:</span> <span class="token string">'c'</span><span class="token punctuation">,</span> length<span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">}</span>
likeArray<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>iterator<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token function-variable function">next</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// return {value: 1, done: true}</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span>value<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> done<span class="token operator">:</span> i<span class="token operator">++</span> <span class="token operator">===</span> <span class="token keyword">this</span><span class="token punctuation">.</span>length<span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>likeArray<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// [ 'a', 'b', 'c' ]</span>
</code></pre></div><p>上面使用遍历器的方法代码看着相对麻烦些，我们可以使用generator</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> likeArray <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token number">0</span><span class="token operator">:</span> <span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token operator">:</span> <span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token operator">:</span> <span class="token string">'c'</span><span class="token punctuation">,</span> length<span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">}</span>

<span class="token comment">//注意： * 和yiled必须同时才有效</span>
likeArray<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>iterator<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span>
  <span class="token keyword">while</span><span class="token punctuation">(</span>i <span class="token operator">!==</span> <span class="token keyword">this</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">yield</span> <span class="token keyword">this</span><span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>likeArray<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// [ 'a', 'b', 'c' ]</span>
</code></pre></div><h3 id="co库"><a href="#co库" class="header-anchor">#</a> co库</h3> <p>使用read</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>promises
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token operator">*</span> <span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span><span class="token punctuation">{</span>
    <span class="token keyword">const</span> name <span class="token operator">=</span> <span class="token keyword">yield</span> fs<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'name.txt'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span>
    <span class="token keyword">const</span> age <span class="token operator">=</span> <span class="token keyword">yield</span> fs<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> age
  <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> it <span class="token operator">=</span> <span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> value<span class="token punctuation">,</span> done <span class="token punctuation">}</span> <span class="token operator">=</span> it<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
value<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> value<span class="token punctuation">,</span> done <span class="token punctuation">}</span> <span class="token operator">=</span> it<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
  value<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// const { value, done } = it.next(res)</span>
    <span class="token comment">// console.log('value', value)</span>

    it<span class="token punctuation">.</span><span class="token function">throw</span><span class="token punctuation">(</span><span class="token string">'发生错误啦'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>这样的使用明显麻烦，如果有多个promise就需要then多次</p> <p>模拟co库</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>promises
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> <span class="token function-variable function">co</span> <span class="token operator">=</span> <span class="token parameter">it</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// 异步迭代的是回调函数</span>
    <span class="token keyword">function</span> <span class="token function">next</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> value<span class="token punctuation">,</span> done <span class="token punctuation">}</span> <span class="token operator">=</span> it<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>done<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>next<span class="token punctuation">,</span> reject<span class="token punctuation">)</span>
      <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token function">resolve</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token operator">*</span> <span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> name <span class="token operator">=</span> <span class="token keyword">yield</span> fs<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'name.txt'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> age <span class="token operator">=</span> <span class="token keyword">yield</span> fs<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span> age
<span class="token punctuation">}</span>

<span class="token function">co</span><span class="token punctuation">(</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">data</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token parameter">err</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><h2 id="promise实战"><a href="#promise实战" class="header-anchor">#</a> promise实战</h2> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span>reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'外部promise'</span><span class="token punctuation">)</span>
  <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'外部第一个then'</span><span class="token punctuation">)</span>
  <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span>reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'内部promise'</span><span class="token punctuation">)</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'内部第一个then'</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'内部第二个then'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'外部第二个then'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'外部第三个then'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'外部第四个then'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>浏览器输出结果</p> <div class="language-js extra-class"><pre class="language-js"><code>外部promise
外部第一个then
内部promise
内部第一个then
外部第二个then
外部第三个then
外部第四个then
内部第二个then
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span><span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>输出结果</p> <div class="language- extra-class"><pre class="language-text"><code>0
1
2
3
4
5
6
</code></pre></div></div> <footer class="page-edit"><!----> <!----></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/front/base/JS深入/36.html" class="prev">
        发布订阅和观察者模式
      </a></span> <span class="next"><a href="/front/base/JS深入/39.html">
        手写常用方法
      </a>
      →
    </span></p></div> </main></div><div class="global-ui"><!----><!----></div></div>
    <script src="/assets/js/app.8c5a7a92.js" defer></script><script src="/assets/js/2.8e30e130.js" defer></script><script src="/assets/js/197.2a8de731.js" defer></script><script src="/assets/js/64.0323ed89.js" defer></script>
  </body>
</html>
